package singleflight;


import utils.ByteArrayUtil;

import java.io.FilterInputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Supplier;

//singleflight 的主数据结构，管理不同 key 的请求(call)
public class CallManage {
    private final ReentrantLock lock;
    private final ConcurrentHashMap<String, Call> callMap;

    public CallManage() {
        lock = new ReentrantLock();
        callMap = new ConcurrentHashMap<>();
    }

    public byte[] run(String key, Supplier<byte[]> func) {
        if (key == null || func == null) {
            System.out.println("key 和 func 不能为空");
            return null;
        }

        Call call;
        lock.lock();
        try {
            // 使用 putIfAbsent 避免多个线程同时创建 Call 对象
            call = callMap.putIfAbsent(key, new Call());
            if (call == null) {
                call = callMap.get(key);
                call.lock();
                try {
                    // 执行任务，设置结果，调用 done()
                    byte[] result = func.get();
                    call.setVal(result);
                    call.done();
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            } else {
                lock.unlock();
            }
        } catch (Exception e) {
            lock.unlock();
            throw e;
        }

        try {
            call.await();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            // 可以添加更多中断处理逻辑，例如抛出运行时异常或退出程序
            throw new RuntimeException("Thread interrupted while waiting for call", e);
        }

        lock.lock();
        try {
            if (call.getVal() == null) {
                // 理论上不会进入这里，因为在 call.await() 之后，call.getVal() 应该已经被设置
                System.out.println("Unexpected: call.getVal() is null");
            }
        } finally {
            lock.unlock();
        }
        return call.getVal();
    }
}
